package Server;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import Client.IClient;

/**
 * Classe Server implementant l'interface Remote IServer
 * @author Jeremy & Alicia
 *
 */
public class Server extends UnicastRemoteObject implements IServer {
	
	private static final long serialVersionUID = 5828760534985216413L;
	/**
	 * Pour chaque sujet de discussion, est associe une liste des Clients, via leur interface Remote
	 */
	private HashMap<String,LinkedList<String>> abonnements;
	/**
	 * Pour chaque login de client est associe une interface Remote de ce client
	 */
	private HashMap<String, IClient> binding;
	/**
	 * Map permettant de mieux gerer les pseudos choisis pars les clients
	 */
	private HashMap<String, Integer> nameUseByClients;
	
	/**
	 * Ip du server
	 */
	private String ip;
	
	/**
	 * Constructeur par defaut du Server
	 * @throws RemoteException
	 */
	public Server(String ipServer) throws RemoteException {
		binding = new HashMap<String, IClient>();
		abonnements = new HashMap<String,LinkedList<String>>();
		
		nameUseByClients = new HashMap<String,Integer>();
		ip = ipServer;
		/*
		 * Trois sujets sont ajout�s par defaut au lancement du serveur
		 */
		abonnements.put("cinema", new LinkedList<String>());
		abonnements.put("musique", new LinkedList<String>());
		abonnements.put("livres", new LinkedList<String>());
	}
	
	/**
	 * Methode appele par les clients lorsqu'ils decident de changer de pseudo
	 * @param login : login du client
	 * @param oldName : nom actuel du client
	 * @param newName : nouveau nom demande par le client
	 * @return le nom valide par le serveur, potentiellement celui demande mais avec un numero si la base est deja utilise
	 */
	public String chooseName(String login, String oldName, String newName) throws RemoteException {
		String correctName = newName;
		if(newName.isEmpty()){
			correctName = "Anonymous";
		}
		
		if(nameUseByClients.containsKey(newName)){
			nameUseByClients.put(newName,nameUseByClients.get(newName)+1);
			correctName += nameUseByClients.get(newName);
		}
		else{
			nameUseByClients.put(newName, 0);
		}
		
		return correctName;
	}
	
	/**
	 * Ajoute un sujet de discussion sur le serveur s'il n'existe pas deja
	 * @param subject : nom du nouveau sujet de discussion
	 */
	public void addSubject(String subject){
		if(!abonnements.containsKey(subject)){
			abonnements.put(subject, new LinkedList<String>());
		}
	}
	
	/**
	 * Fournit la liste de sujets actuellement present sur le serveur
	 * @return une liste de string, les sujets
	 */
	public List<String> getSubjects(){
		List<String> list = new LinkedList<String>();
		list.addAll(abonnements.keySet());
		return list;
	}

	/**
	 * Methode appelee par le client demandant au serveur de diffuser un message au autres clients suivant le sujet
	 * @param fenetre: fenetre dans laquel le message doit etre affiche
	 * @param message: message a diffuser
	 */
	public void diffuserMessage(String fenetre, String message) throws RemoteException {
		IClient client = null;
		for(String clientLogin : abonnements.get(fenetre)){
			try {
				client = ((IClient)Naming.lookup("//localhost/Client"+clientLogin));
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (NotBoundException e) {
				e.printStackTrace();
			}
			client.publierMessage(fenetre, message);
		}
		
	}

	/**
	 * Demande du client pour etre associe a un sujet de discussion
	 * @param loginClient : login du client
	 * @param subject : sujet auquel il souhaite etre associe
	 */
	public void abonneMoi(String loginClient, String subject) {
		IClient client = null;
		try {
			client = (IClient) Naming.lookup("//localhost/Client"+loginClient);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (RemoteException e){
			e.printStackTrace();
		} catch (NotBoundException e){
			e.printStackTrace();
		}
		String clientLogin = "";
		try {
			clientLogin = client.getLogin();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		if(!abonnements.get(subject).contains(clientLogin)){
			abonnements.get(subject).add(clientLogin);
		}
	}
	
	/**
	 * Demande du client pour etre retirer d'un sujet de discussion
	 * @param loginClient : login du client
	 * @param subject : sujet auquel il souhaite etre retirer
	 */
	public void desabonneMoi(String loginClient, String subject) {
		try {
			abonnements.get(subject).remove((IClient) Naming.lookup("//localhost/Client"+loginClient));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (RemoteException e){
			e.printStackTrace();
		} catch (NotBoundException e){
			e.printStackTrace();
		}
	}
	
	private boolean isAbonnedTo(String client, String subject){
		return false;
	}

	/**
	 * 
	 */
	public void binder(String loginClient) {
		try {
			binding.put(loginClient, (IClient) Naming.lookup("//"+ip+"/Client"+loginClient));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (RemoteException e) {
			e.printStackTrace();
		} catch (NotBoundException e) {
			e.printStackTrace();
		}
	}
}
